package org.osomit.sacct.security.utils;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;

/**
 * @author Jian Fang (John.Jian.Fang@gmail.com)
 *
 * Date: Jun 26, 2009
 */
public class Serializer {

    @SuppressWarnings("boxing")
    public static <T extends Serializable> byte[] serialize(T target, boolean verbose) throws IOException{
        long start, end, duration;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream( bos );

        if(verbose)
            System.out.println( "Serializing ......");

        start = System.nanoTime();
        oos.writeObject(target);
        end = System.nanoTime();

        oos.flush();
        oos.close();

        duration = end - start;
        if(verbose){
            System.out.println("Finish Serializing " + target.getClass().getSimpleName() );
            System.out.printf("Serialization time: %.3fms\n", duration/1000000.0);
        }

        return bos.toByteArray();
    }

    @SuppressWarnings({ "boxing", "unchecked" })
    public static <T extends Serializable> T deserialize(byte[] bytes, boolean verbose) throws IOException, ClassNotFoundException{
        long start, end, duration;
        T target = null;

        ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
        BufferedInputStream bis = new BufferedInputStream( bais );
        ObjectInputStream ois = new ObjectInputStream(bis);

        if(verbose)
            System.out.println( "Deserializing ......" );
        start = System.nanoTime();

        target = (T) ois.readObject();

        end = System.nanoTime();

        ois.close();

        duration = end - start;
        if(verbose){
            System.out.println("Finish deserializing" + target.getClass().getSimpleName() );
            System.out.printf("Deserialization time: %.3fms\n", duration/1000000.0);
        }

        return target;
    }

    public static byte[] decompress(byte[] input) throws IOException {
        ByteArrayInputStream bais = new ByteArrayInputStream( input );
        BufferedInputStream bis = new BufferedInputStream( bais );
        InflaterInputStream iis = new InflaterInputStream( bis );

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer=new byte[input.length];

        int cnt;
        while ((cnt=iis.read(buffer))!=-1) {
            out.write(buffer,0,cnt);
        }

        iis.close();
        //check this
        out.close();

        return out.toByteArray();
    }

    public static byte[] compress(byte[] input) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DeflaterOutputStream dos = new DeflaterOutputStream( bos );
        dos.write(input);

        dos.flush();
        dos.close();

        return bos.toByteArray();
    }

    @SuppressWarnings("boxing")
    public static <T extends Serializable> byte[] serializeAndCompress(T target, boolean verbose) throws IOException{
        long start, end, duration;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DeflaterOutputStream dos = new DeflaterOutputStream( bos );
        ObjectOutputStream oos = new ObjectOutputStream( dos );

        if(verbose)
            System.out.println( "Compressing ......");

        start = System.nanoTime();
        oos.writeObject(target);
        end = System.nanoTime();

        oos.flush();
        oos.close();

        duration = end - start;
        if(verbose){
            System.out.println("Finish Compressing " + target.getClass().getSimpleName() );
            System.out.printf("Compression time: %.3fms\n", duration/1000000.0);
            System.out.println("Size after Compression: " + bos.toByteArray().length);
        }

        return bos.toByteArray();
    }

    @SuppressWarnings({ "boxing", "unchecked" })
    public static <T extends Serializable> T decompressAndDeserialize(byte[] bytes, boolean verbose) throws IOException, ClassNotFoundException{
        long start, end, duration;
        T target = null;

        ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
        BufferedInputStream bis = new BufferedInputStream( bais );
        ObjectInputStream ois = new ObjectInputStream( new InflaterInputStream( bis ) );

        if(verbose)
            System.out.println( "Decompressing ......" );
        start = System.nanoTime();

        target = (T) ois.readObject();

        end = System.nanoTime();

        ois.close();

        duration = end - start;
        if(verbose){
            System.out.println("Finish decompressing" + target.getClass().getSimpleName() );
            System.out.printf("Decompression time: %.3fms\n", duration/1000000.0);
        }

        return target;
    }    
}
